package cn.yq.share.config;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.transaction.jta.JtaTransactionManager;

import javax.sql.DataSource;
import javax.transaction.UserTransaction;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author 007
 * @version V1.0
 * @Description:
 * @date 2018/11/22 14:28
 */
@Configuration
public class DruidConfig {

//    private Logger logger = LoggerFactory.getLogger(DruidConfig.class);
//
//    @Value("${spring.datasource.url:#{null}}")
//    private String dbUrl;
//    @Value("${spring.datasource.username: #{null}}")
//    private String username;
//    @Value("${spring.datasource.password:#{null}}")
//    private String password;
//    @Value("${spring.datasource.driverClassName:#{null}}")
//    private String driverClassName;
//
//    @Value("${spring.datasource2.url:#{null}}")
//    private String dbUrl2;
//    @Value("${spring.datasource2.username: #{null}}")
//    private String username2;
//    @Value("${spring.datasource2.password:#{null}}")
//    private String password2;
//    @Value("${spring.datasource2.driverClassName:#{null}}")
//    private String driverClassName2;
//
//    @Value("${spring.datasource.initialSize:#{null}}")
//    private Integer initialSize;
//    @Value("${spring.datasource.minIdle:#{null}}")
//    private Integer minIdle;
//    @Value("${spring.datasource.maxActive:#{null}}")
//    private Integer maxActive;
//    @Value("${spring.datasource.maxWait:#{null}}")
//    private Integer maxWait;
//    @Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
//    private Integer timeBetweenEvictionRunsMillis;
//    @Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
//    private Integer minEvictableIdleTimeMillis;
//    @Value("${spring.datasource.validationQuery:#{null}}")
//    private String validationQuery;
//    @Value("${spring.datasource.testWhileIdle:#{null}}")
//    private Boolean testWhileIdle;
//    @Value("${spring.datasource.testOnBorrow:#{null}}")
//    private Boolean testOnBorrow;
//    @Value("${spring.datasource.testOnReturn:#{null}}")
//    private Boolean testOnReturn;
//    @Value("${spring.datasource.poolPreparedStatements:#{null}}")
//    private Boolean poolPreparedStatements;
//    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
//    private Integer maxPoolPreparedStatementPerConnectionSize;
//    @Value("${spring.datasource.filters:#{null}}")
//    private String filters;
//    @Value("{spring.datasource.connectionProperties:#{null}}")
//    private String connectionProperties;
//
//    @Bean
//    @Primary
//    public DataSource dataSource(){
//        DruidDataSource datasource = new DruidDataSource();
//
//        datasource.setUrl(this.dbUrl);
//        datasource.setUsername(username);
//        datasource.setPassword(password);
//        datasource.setDriverClassName(driverClassName);
//        //configuration
//        if(initialSize != null) {
//            datasource.setInitialSize(initialSize);
//        }
//        if(minIdle != null) {
//            datasource.setMinIdle(minIdle);
//        }
//        if(maxActive != null) {
//            datasource.setMaxActive(maxActive);
//        }
//        if(maxWait != null) {
//            datasource.setMaxWait(maxWait);
//        }
//        if(timeBetweenEvictionRunsMillis != null) {
//            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
//        }
//        if(minEvictableIdleTimeMillis != null) {
//            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
//        }
//        if(validationQuery!=null) {
//            datasource.setValidationQuery(validationQuery);
//        }
//        if(testWhileIdle != null) {
//            datasource.setTestWhileIdle(testWhileIdle);
//        }
//        if(testOnBorrow != null) {
//            datasource.setTestOnBorrow(testOnBorrow);
//        }
//        if(testOnReturn != null) {
//            datasource.setTestOnReturn(testOnReturn);
//        }
//        if(poolPreparedStatements != null) {
//            datasource.setPoolPreparedStatements(poolPreparedStatements);
//        }
//        if(maxPoolPreparedStatementPerConnectionSize != null) {
//            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
//        }
//
//        if(connectionProperties != null) {
//            datasource.setConnectionProperties(connectionProperties);
//        }
//
//        List<Filter> filters = new ArrayList<>();
//        filters.add(statFilter());
//        filters.add(wallFilter());
//        datasource.setProxyFilters(filters);
//
//        return datasource;
//    }
//
//    @Bean
//    public DataSource dataSource2(){
//        DruidDataSource datasource = new DruidDataSource();
//
//        datasource.setUrl(this.dbUrl2);
//        datasource.setUsername(username2);
//        datasource.setPassword(password2);
//        datasource.setDriverClassName(driverClassName2);
//        //configuration
//        if(initialSize != null) {
//            datasource.setInitialSize(initialSize);
//        }
//        if(minIdle != null) {
//            datasource.setMinIdle(minIdle);
//        }
//        if(maxActive != null) {
//            datasource.setMaxActive(maxActive);
//        }
//        if(maxWait != null) {
//            datasource.setMaxWait(maxWait);
//        }
//        if(timeBetweenEvictionRunsMillis != null) {
//            datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
//        }
//        if(minEvictableIdleTimeMillis != null) {
//            datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
//        }
//        if(validationQuery!=null) {
//            datasource.setValidationQuery(validationQuery);
//        }
//        if(testWhileIdle != null) {
//            datasource.setTestWhileIdle(testWhileIdle);
//        }
//        if(testOnBorrow != null) {
//            datasource.setTestOnBorrow(testOnBorrow);
//        }
//        if(testOnReturn != null) {
//            datasource.setTestOnReturn(testOnReturn);
//        }
//        if(poolPreparedStatements != null) {
//            datasource.setPoolPreparedStatements(poolPreparedStatements);
//        }
//        if(maxPoolPreparedStatementPerConnectionSize != null) {
//            datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
//        }
//
//        if(connectionProperties != null) {
//            datasource.setConnectionProperties(connectionProperties);
//        }
//
//        List<Filter> filters = new ArrayList<>();
//        filters.add(statFilter());
//        filters.add(wallFilter());
//        datasource.setProxyFilters(filters);
//
//        return datasource;
//    }

    @Bean(name = "systemDataSource")
    @Primary
    @Autowired
    public DataSource systemDataSource(Environment env) {
        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        Properties prop = build(env, "spring.datasource.druid.systemDB.");
        ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        ds.setUniqueResourceName("systemDB");
        ds.setPoolSize(5);
        ds.setXaProperties(prop);
        return ds;

    }

    @Autowired
    @Bean(name = "businessDataSource")
    public AtomikosDataSourceBean businessDataSource(Environment env) {

        AtomikosDataSourceBean ds = new AtomikosDataSourceBean();
        Properties prop = build(env, "spring.datasource.druid.businessDB.");
        ds.setXaDataSourceClassName("com.alibaba.druid.pool.xa.DruidXADataSource");
        ds.setUniqueResourceName("businessDB");
        ds.setPoolSize(5);
        ds.setXaProperties(prop);

        return ds;
    }


    /**
     * 注入事物管理器
     * @return
     */
    @Bean(name = "xatx")
    public JtaTransactionManager regTransactionManager () {
        UserTransactionManager userTransactionManager = new UserTransactionManager();
        UserTransaction userTransaction = new UserTransactionImp();
        return new JtaTransactionManager(userTransaction, userTransactionManager);
    }


    private Properties build(Environment env, String prefix) {

        Properties prop = new Properties();
        prop.put("url", env.getProperty(prefix + "url"));
        prop.put("username", env.getProperty(prefix + "username"));
        prop.put("password", env.getProperty(prefix + "password"));
        prop.put("driverClassName", env.getProperty(prefix + "driverClassName", ""));
        prop.put("initialSize", env.getProperty(prefix + "initialSize", Integer.class));
        prop.put("maxActive", env.getProperty(prefix + "maxActive", Integer.class));
        prop.put("minIdle", env.getProperty(prefix + "minIdle", Integer.class));
        prop.put("maxWait", env.getProperty(prefix + "maxWait", Integer.class));
        prop.put("poolPreparedStatements", env.getProperty(prefix + "poolPreparedStatements", Boolean.class));

        prop.put("maxPoolPreparedStatementPerConnectionSize",
                env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class));

        prop.put("maxPoolPreparedStatementPerConnectionSize",
                env.getProperty(prefix + "maxPoolPreparedStatementPerConnectionSize", Integer.class));
        prop.put("validationQuery", env.getProperty(prefix + "validationQuery"));
        prop.put("validationQueryTimeout", env.getProperty(prefix + "validationQueryTimeout", Integer.class));
        prop.put("testOnBorrow", env.getProperty(prefix + "testOnBorrow", Boolean.class));
        prop.put("testOnReturn", env.getProperty(prefix + "testOnReturn", Boolean.class));
        prop.put("testWhileIdle", env.getProperty(prefix + "testWhileIdle", Boolean.class));
        prop.put("timeBetweenEvictionRunsMillis",
                env.getProperty(prefix + "timeBetweenEvictionRunsMillis", Integer.class));
        prop.put("minEvictableIdleTimeMillis", env.getProperty(prefix + "minEvictableIdleTimeMillis", Integer.class));
        prop.put("filters", env.getProperty(prefix + "filters"));

        return prop;
    }


    @Bean
    public ServletRegistrationBean druidServlet() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");

        //控制台管理用户，加入下面2行 进入druid后台就需要登录
        //servletRegistrationBean.addInitParameter("loginUsername", "admin");
        //servletRegistrationBean.addInitParameter("loginPassword", "admin");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        filterRegistrationBean.addInitParameter("profileEnable", "true");
        return filterRegistrationBean;
    }

    @Bean
    public StatFilter statFilter(){
        StatFilter statFilter = new StatFilter();
        statFilter.setLogSlowSql(true); //slowSqlMillis用来配置SQL慢的标准，执行时间超过slowSqlMillis的就是慢。
        statFilter.setMergeSql(true); //SQL合并配置
        statFilter.setSlowSqlMillis(1000);//slowSqlMillis的缺省值为3000，也就是3秒。
        return statFilter;
    }

    @Bean
    public WallFilter wallFilter(){
        WallFilter wallFilter = new WallFilter();
        //允许执行多条SQL
        WallConfig config = new WallConfig();
        config.setMultiStatementAllow(true);
        wallFilter.setConfig(config);
        return wallFilter;
    }
}
